#include "renderthread.h"
#include <QPainter>
#include <QDebug>
#include <QTime>
#include <iostream>
#include "pbrt.h"
#include "geometry.h"
#include "intersection.h"

using namespace std;

RenderThread::RenderThread(Scene *sc, QObject *parent) :
    QThread(parent)
{
    restart = false;
    abort = false;
    scene = sc;
}


RenderThread::~RenderThread()
{
    mutex.lock();
    abort = true;
    condition.wakeOne();
    mutex.unlock();
    wait();
}

void RenderThread::render()
{
    QMutexLocker locker(&mutex);

    if (!isRunning()) {
        start(LowPriority);
    } else {
        restart = true;
        condition.wakeOne();
    }
}

void RenderThread::run()
{
    forever {
        mutex.lock();

        // TODO: copy scene

        mutex.unlock();

        // TODO: parameterizable size
        QImage image(QSize(1024,1024), QImage::Format_RGB32);

        QPainter p( &image );
        p.setBrush(QBrush(Qt::red, Qt::SolidPattern));
        Intersection *isect = new Intersection();

        QTime t;
        t.start();

        for (int y = 0; y < 1024; ++y) {
            for (int x = 0; x < 1024; ++x) {
                float red = 0, green = 0, blue = 0;
                float coef = 1.0f;
                int level = 0;

                Ray viewRay(Point (x, y, -1000.0f), Vector(0, 0, 1), 0);

                do {

                    if ( ! scene->Intersect(viewRay,isect) ) break;

                    Point newStart = isect->dg.p;
                    Normal n = isect->dg.nn;

                    Material *currentMat = isect->primitive->getMaterial();

                    for (unsigned j = 0; j < scene->lights.size() ; ++j) {
                        Light *current = scene->lights[j];
                        Vector dist = current->p - newStart;

                        if( Dot( n, dist) <= 0 )
                            continue;

                        float t = sqrt( Dot(dist, dist) );

                        if(t <= 0.0f)
                            continue;

                        Ray lightRay(newStart, Normalize(dist), isect->rayEpsilon);

                        bool inShadow = false;
                        if(scene->IntersectP(lightRay)) inShadow = true;

                        if ( !inShadow ) {
                            float lambert = Dot(lightRay.d, n) * coef;
                            red += lambert * current->c.red * currentMat->c.red;
                            green += lambert * current->c.green * currentMat->c.green;
                            blue += lambert * current->c.blue * currentMat->c.blue;
                        }

                    }


                    coef *= currentMat->reflection;
                    float reflet = 2.0f * (Dot(viewRay.d, n));

                    Vector nvec(n);
                    Vector dir = viewRay.d - nvec*reflet;

                    viewRay = Ray(newStart, dir, isect->rayEpsilon );

                    level++;
                } while ((coef > 0.0f) && (level < 10));

                QColor col(  Clamp( (int)(red*255),0,255)
                            ,Clamp( (int)(green*255),0,255)
                            ,Clamp( (int)(blue*255),0,255)
                             );
                p.setPen(col);
                p.drawPoint(x,y);

            }
        }

        QString renderTime("Time elapsed : ");
        renderTime = renderTime + QString::number( t.elapsed() ) + " ms";

        p.setPen(Qt::yellow);
        p.setFont(QFont("Times", 20, QFont::Bold));
        p.drawText(200,250, renderTime);


        if (restart)
            break;

        if (abort)
            return;

        if (!restart)
            emit renderedImage(image);

        mutex.lock();

        if (!restart)
            condition.wait(&mutex);

        restart = false;
        mutex.unlock();
    }
}
